<Designer(GetType(WizardDesigner)), DefaultEvent("ValidatePage")> _
Public Class Wizard
    Inherits System.Windows.Forms.UserControl

    'Buttons
    Friend WithEvents btnBack, btnNext, btnCancel As Button

    'Pages
    Private _Pages As WizardPageCollection
    Friend intSelectedPage As Integer = -1
    Private _strTitle As String = "Sample"
    Private summaryArgs As WizardPageSummaryEventArgs
    Private afterPageArgs As WizardPageEventArgs
    Private _CloseForm As Boolean = True

    'Drawing
    Private HeadingStringFormat, DescriptionStringFormat As StringFormat
    Private _imgBannerBitmap As Image = Nothing

    'Welcome page
    Private _imgWelcomeBitmap As Image = Nothing
    Private _strWelcomeText As String = "Replace this text with an introductory message for the wizard."

    'Events
    Public Event BeforeSummaryPageDisplayed(ByVal sender As Object, ByVal e As WizardPageSummaryEventArgs)
    Public Event BeforePageDisplayed(ByVal sender As Object, ByVal e As WizardPageDisplayedEventArgs)
    Public Event AfterPageDisplayed(ByVal sender As Object, ByVal e As WizardPageEventArgs)
    Public Event ValidatePage(ByVal sender As Object, ByVal e As WizardPageValidateEventArgs)
    Public Event Finished(ByVal sender As Object, ByVal e As System.EventArgs)
    Public Event Cancelled(ByVal sender As Object, ByVal e As System.EventArgs)

    'Strings
    Private _BackText As String = "&Back"
    Private _NextText As String = "&Next"
    Private _FinishText As String = "&Finish"
    Private _CancelText As String = "&Cancel"
    Public WelcomeHeadingText As String = "Welcome to the <data> Wizard"
    Public FinishHeadingText As String = "Completing the <data> Wizard"
    Public FinishSuccessText As String = "You have successfully completed the <data> Wizard."
    Public FinishCloseText As String = "To close this wizard, click Finish."

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call
        Initialize()
    End Sub

    'UserControl overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        components = New System.ComponentModel.Container()
    End Sub

#End Region

    Private Function ShouldSerializeBackText() As Boolean
        Return False
    End Function

    Private Function ShouldSerializeCancelText() As Boolean
        Return False
    End Function

    Private Function ShouldSerializeFinishText() As Boolean
        Return False
    End Function

    Private Function ShouldSerializeNextText() As Boolean
        Return False
    End Function

    <Browsable(False)> _
    Public ReadOnly Property CurrentPage() As WizardPage
        Get
            If (intSelectedPage >= 0 And intSelectedPage <= Pages.Count) Then
                Return Pages(intSelectedPage)
            Else
                Return Nothing
            End If
        End Get
    End Property

    <Browsable(False)> _
    Public Property BackText() As String
        Get
            Return _BackText
        End Get
        Set(ByVal Value As String)
            _BackText = Value
            If Not btnBack Is Nothing Then btnBack.Text = _BackText
        End Set
    End Property

    <Browsable(False)> _
    Public Property CancelText() As String
        Get
            Return _CancelText
        End Get
        Set(ByVal Value As String)
            _CancelText = Value
            If Not btnCancel Is Nothing Then btnCancel.Text = Value
        End Set
    End Property

    <Browsable(False)> _
    Public Property FinishText() As String
        Get
            Return _FinishText
        End Get
        Set(ByVal Value As String)
            If Not btnNext Is Nothing Then
                If btnNext.Text = _FinishText Then btnNext.Text = Value
            End If
            _FinishText = Value
        End Set
    End Property

    <Browsable(False)> _
    Public Property NextText() As String
        Get
            Return _NextText
        End Get
        Set(ByVal Value As String)
            If Not btnNext Is Nothing Then
                If btnNext.Text = _NextText & " >" Then btnNext.Text = Value & " >"
            End If
            _NextText = Value
        End Set
    End Property

    <DefaultValue(True), Category("Wizard"), Description("If True, the wizard applies either a DialogResult.Ok or DialogResult.Cancel to the form automatically.")> _
    Public Property CloseForm() As Boolean
        Get
            Return _CloseForm
        End Get
        Set(ByVal Value As Boolean)
            _CloseForm = Value
        End Set
    End Property

    <Category("Wizard"), Description("The text that appears as an introduction to the wizard on the welcome page.")> _
    Public Property WelcomeText() As String
        Get
            Return _strWelcomeText
        End Get
        Set(ByVal Value As String)
            _strWelcomeText = Value
            If intSelectedPage = -1 Then Invalidate()
        End Set
    End Property

    Public Sub EnableNextButton(ByVal Enabled As Boolean)
        If btnNext.Text = _NextText & " >" Then
            btnNext.Enabled = Enabled
        End If
    End Sub

    <DefaultValue("Sample"), Category("Wizard"), Description("The Title of the wizard.")> _
    Public Property Title() As String
        Get
            Return _strTitle
        End Get
        Set(ByVal Value As String)
            _strTitle = Value
            If intSelectedPage = -1 Or intSelectedPage = Pages.Count Then Invalidate()
        End Set
    End Property

    <Category("Wizard"), Description("The 164 x 313 pixel image to display in the welcome page.")> _
    Public Property WelcomeBitmap() As Image
        Get
            Return _imgWelcomeBitmap
        End Get
        Set(ByVal Value As Image)
            If Value Is Nothing Then
                _imgWelcomeBitmap = Value
            Else
                If Value.Width <> 164 Or Value.Height <> 313 Then
                    Throw New ArgumentException("Bitmap must be 164 x 313 pixels.")
                Else
                    _imgWelcomeBitmap = Value
                    If intSelectedPage = -1 Then Invalidate()
                End If
            End If
        End Set
    End Property

    <Category("Wizard"), Description("The 49 x 49 pixel image to display in the banners on wizard pages.")> _
    Public Property BannerBitmap() As Image
        Get
            Return _imgBannerBitmap
        End Get
        Set(ByVal Value As Image)
            If Value Is Nothing Then
                _imgBannerBitmap = Value
            Else
                If Value.Width <> 49 Or Value.Height <> 49 Then
                    Throw New ArgumentException("Bitmap must be 49 x 49 pixels.")
                Else
                    _imgBannerBitmap = Value
                    Invalidate()
                End If
            End If
        End Set
    End Property

    Private Sub Initialize()
        'Set drawing styles
        SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        SetStyle(ControlStyles.DoubleBuffer, True)

        'Initialize string formats
        HeadingStringFormat = New StringFormat(StringFormatFlags.NoWrap)
        DescriptionStringFormat = New StringFormat

        'Initialize pages
        _Pages = New WizardPageCollection(Me)
    End Sub

    Private Function ShouldSerializeControls() As Boolean
        Return False
    End Function

    Private Sub DrawIntroOutro(ByVal g As Graphics)
        Dim wrct As Rectangle
        Dim headerFont As Font
        Dim b As Brush

        'Draw welcome image and white background
        wrct = ClientRectangle
        wrct.Height = ClientRectangle.Height - 47
        g.FillRectangle(Brushes.White, wrct)
        wrct = New Rectangle(0, 0, 164, ClientRectangle.Height - 47)
        b = New SolidBrush(Color.FromArgb(0, 0, 64))
        g.FillRectangle(b, wrct)
        b.Dispose()
        If Not _imgWelcomeBitmap Is Nothing Then
            g.DrawImage(_imgWelcomeBitmap, New Rectangle(wrct.Location, New Size(_imgWelcomeBitmap.Width, _imgWelcomeBitmap.Height)))
        End If

        If intSelectedPage = -1 Then
            'Draw heading text
            headerFont = New Font("Verdana", 12, FontStyle.Bold)
            wrct = New Rectangle(172, 14, ClientRectangle.Width - 182, 58)
            g.DrawString(WelcomeHeadingText.Replace("<data>", _strTitle), headerFont, Brushes.Black, RectangleF.op_Implicit(wrct), DescriptionStringFormat)

            'Draw welcome text
            wrct = New Rectangle(172, 78, ClientRectangle.Width - 182, ClientRectangle.Height - 137)
            g.DrawString(_strWelcomeText, Font, Brushes.Black, RectangleF.op_Implicit(wrct), DescriptionStringFormat)
        Else
            'Draw heading text
            headerFont = New Font("Verdana", 12, FontStyle.Bold)
            wrct = New Rectangle(172, 14, ClientRectangle.Width - 182, 58)
            g.DrawString(FinishHeadingText.Replace("<data>", _strTitle), headerFont, Brushes.Black, RectangleF.op_Implicit(wrct), DescriptionStringFormat)

            'Draw success text
            wrct = New Rectangle(172, 78, ClientRectangle.Width - 182, 32)
            g.DrawString(FinishSuccessText.Replace("<data>", _strTitle), Font, Brushes.Black, RectangleF.op_Implicit(wrct), DescriptionStringFormat)
            wrct = New Rectangle(172, ClientRectangle.Height - 70, 301, 16)
            g.DrawString(FinishCloseText, Font, Brushes.Black, RectangleF.op_Implicit(wrct), DescriptionStringFormat)

            If summaryArgs.h.Count <> 0 Then
                'Draw name/value introduction
                wrct = New Rectangle(172, 115, ClientRectangle.Width - 182, 32)
                g.DrawString(summaryArgs.NameValueIntroduction, Font, Brushes.Black, RectangleF.op_Implicit(wrct), DescriptionStringFormat)

                'Draw summary text
                DrawSummaryText(g)
            End If
        End If

        headerFont.Dispose()
    End Sub

    Private Sub DrawSummaryText(ByVal g As Graphics)
        Dim wrct As Rectangle
        Dim oldClip As Region
        Dim intX, intY, intMaxWidth, intMaxHeight As Integer
        Dim myEnumerator As IDictionaryEnumerator

        'Create clipping rectangle
        oldClip = g.Clip
        wrct = New Rectangle(172, 140, ClientRectangle.Width - 182, ClientRectangle.Height - 170)
        g.Clip = New Region(wrct)

        'Get maximum width
        intMaxWidth = 0
        myEnumerator = summaryArgs.h.GetEnumerator()
        Do While myEnumerator.MoveNext()
            intX = Convert.ToInt32(g.MeasureString(DirectCast(myEnumerator.Key, String) & ":", Font, New SizeF(100, 20)).Width)
            If intX > intMaxWidth Then intMaxWidth = intX
        Loop
        intMaxHeight = Convert.ToInt32(g.MeasureString("|", Font, New SizeF(100, 100)).Height)

        'Draw stuff
        intY = 140
        myEnumerator = summaryArgs.h.GetEnumerator()
        Do While myEnumerator.MoveNext()
            g.DrawString(DirectCast(myEnumerator.Key, String) & ":", Font, Brushes.Black, 172, intY)
            g.DrawString(DirectCast(myEnumerator.Value, String), Font, Brushes.Black, 172 + intMaxWidth + 5, intY)
            intY = intY + intMaxHeight + 2
        Loop

        'Restore old clipping rectangle
        g.Clip = oldClip
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        Dim wrct As Rectangle
        Dim headerFont, hyperlinkFont As Font
        Dim centreStringFormat As StringFormat
        Dim p As WizardPage

        MyBase.OnPaint(e)

        'Draw 3d lines
        wrct = New Rectangle(0, ClientRectangle.Height - 46, ClientRectangle.Width, 46)
        e.Graphics.FillRectangle(SystemBrushes.Control, wrct)
        e.Graphics.DrawLine(SystemPens.ControlDark, 0, ClientRectangle.Height - 47, ClientRectangle.Width, ClientRectangle.Height - 47)
        e.Graphics.DrawLine(SystemPens.ControlLightLight, 0, ClientRectangle.Height - 46, ClientRectangle.Width, ClientRectangle.Height - 46)

        'Draw buttons if in design mode
        If DesignMode Then
            hyperlinkFont = New Font(Font, FontStyle.Underline)

            Dim s As New StringFormat
            s.Alignment = StringAlignment.Center
            s.LineAlignment = StringAlignment.Center
            e.Graphics.DrawString("< Back", hyperlinkFont, Brushes.Blue, RectangleF.op_Implicit(btnBack.Bounds), s)
            e.Graphics.DrawString("Next >", hyperlinkFont, Brushes.Blue, RectangleF.op_Implicit(btnNext.Bounds), s)

            hyperlinkFont.Dispose()
        End If

        If intSelectedPage = -1 Or intSelectedPage = Pages.Count Then
            DrawIntroOutro(e.Graphics)
        ElseIf intSelectedPage > -1 And intSelectedPage < Pages.Count Then
            headerFont = New Font(Font, FontStyle.Bold)
            p = Pages(intSelectedPage)

            'Fill white banner background and draw divider lines
            wrct = ClientRectangle
            wrct.Height = 58
            e.Graphics.FillRectangle(Brushes.White, RectangleF.op_Implicit(wrct))
            e.Graphics.DrawLine(SystemPens.ControlDark, 0, 58, ClientRectangle.Width, 58)
            e.Graphics.DrawLine(SystemPens.ControlLightLight, 0, 59, ClientRectangle.Width, 59)

            'Draw text
            wrct = New Rectangle(21, 9, 420, 186)
            e.Graphics.DrawString(p.Heading, headerFont, Brushes.Black, RectangleF.op_Implicit(wrct), HeadingStringFormat)
            wrct = New Rectangle(43, 24, 398, 30)
            e.Graphics.DrawString(p.Description, Font, Brushes.Black, RectangleF.op_Implicit(wrct), DescriptionStringFormat)

            'Draw image
            wrct = New Rectangle(ClientRectangle.Right - 54, 5, 49, 49)
            e.Graphics.FillRectangle(Brushes.Navy, wrct)
            If Not _imgBannerBitmap Is Nothing Then
                e.Graphics.DrawImage(_imgBannerBitmap, wrct)
            End If

            If DesignMode Then
                centreStringFormat = New StringFormat
                centreStringFormat.Alignment = StringAlignment.Center
                centreStringFormat.LineAlignment = StringAlignment.Center

                'Draw current page indicator
                wrct = btnNext.Bounds
                wrct.X = btnNext.Right + 5
                wrct.Width = ClientRectangle.Width - btnNext.Right - 5
                e.Graphics.DrawString("Page " & (intSelectedPage + 1).ToString() & " of " & Pages.Count.ToString(), Font, Brushes.Black, RectangleF.op_Implicit(wrct), centreStringFormat)

                centreStringFormat.Dispose()
            End If

            headerFont.Dispose()
        ElseIf intSelectedPage = Pages.Count Then

        End If
    End Sub

    Friend Sub PageAdded(ByVal Page As WizardPage)
        'Add page to control
        If Not Controls.Contains(Page) Then Controls.Add(Page)
        Page.Location = New Point(21, 71)
        Page.Size = New Size(ClientRectangle.Width - 41, ClientRectangle.Height - 130)
        Page.Visible = False

        'Select it if it there isn't already a selected page
        'If intSelectedPage = -1 Then
        '    intSelectedPage = Pages.IndexOf(Page)
        '    UpdatePage()
        'End If

        Page.Wizard = Me
    End Sub

    Friend Sub PageRemoved(ByVal Page As WizardPage, ByVal OldIndex As Integer)
        'Remove page from control
        If Controls.Contains(Page) Then Controls.Remove(Page)

        'Select next
        If intSelectedPage > Pages.Count - 1 Then intSelectedPage = Pages.Count - 1
        UpdatePage()

        Page.Wizard = Nothing
    End Sub

    Friend Sub UpdatePage()
        Dim p As WizardPage

        If Not IsHandleCreated Then Exit Sub

        For Each p In Pages
            If Pages.IndexOf(p) <> intSelectedPage Then p.Visible = False
        Next

        If intSelectedPage <> -1 And intSelectedPage <> Pages.Count Then Pages(intSelectedPage).Visible = True
        Invalidate()

        'Fix buttons
        If intSelectedPage = -1 Then btnBack.Enabled = False
        If intSelectedPage = Pages.Count And Pages.Count <> 0 Then
            btnNext.Text = _FinishText
        Else
            btnNext.Text = _NextText & " >"
        End If
        If Pages.Count = 0 Then btnNext.Enabled = False
    End Sub

    Private Sub btnBack_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnBack.Click
        'If we're on the last page
        If intSelectedPage = Pages.Count Then
            intSelectedPage -= summaryArgs.BackSteps
            intSelectedPage += 1
            If intSelectedPage < 0 Then intSelectedPage = 0
            If intSelectedPage > Pages.Count Then intSelectedPage = Pages.Count
            intSelectedPage -= 1
        Else
            intSelectedPage -= afterPageArgs.BackSteps
        End If

        'Move on
        If intSelectedPage < -1 Then intSelectedPage = -1
        btnNext.Enabled = True
        UpdatePage()
        If intSelectedPage > -1 Then
            afterPageArgs = New WizardPageEventArgs(Pages(intSelectedPage))
            RaiseEvent AfterPageDisplayed(Me, afterPageArgs)
        End If
    End Sub

    Private Sub btnNext_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnNext.Click
        Dim eap As WizardPageDisplayedEventArgs
        Dim eav As WizardPageValidateEventArgs

        'If we're finishing
        If btnNext.Text = _FinishText Then
            If _CloseForm And Not (ParentForm Is Nothing) Then
                ParentForm.DialogResult = DialogResult.OK
            Else
                RaiseEvent Finished(Me, EventArgs.Empty)
            End If
            Return
        End If

        'Perform validation
        If intSelectedPage <> -1 Then
            eav = New WizardPageValidateEventArgs(Pages(intSelectedPage), intSelectedPage + 2)
            RaiseEvent ValidatePage(Me, eav)
            If Not eav.Valid Then Return

            'If next page is out of range
            If eav.NextPage < 1 Or eav.NextPage > Pages.Count + 1 Then
                Throw New ArgumentException("Page is out of bounds.")
            End If

            intSelectedPage = eav.NextPage - 1
        Else
            intSelectedPage += 1
        End If

        'Move on
        If intSelectedPage < Pages.Count Then
            eap = New WizardPageDisplayedEventArgs(Pages(intSelectedPage))
            RaiseEvent BeforePageDisplayed(Me, eap)
            If eap.Cancel Then
                intSelectedPage -= 1
                Return
            End If
        Else
            summaryArgs = New WizardPageSummaryEventArgs
            RaiseEvent BeforeSummaryPageDisplayed(Me, summaryArgs)
        End If

        'Finish off
        btnBack.Enabled = True
        btnNext.Enabled = True
        UpdatePage()
        If intSelectedPage < Pages.Count Then
            If eap.DisableBack Then btnBack.Enabled = False
            If eap.DisableNext Then btnNext.Enabled = False
        End If

        'Raise after displayed event
        If intSelectedPage < Pages.Count Then
            afterPageArgs = New WizardPageEventArgs(Pages(intSelectedPage))
            RaiseEvent AfterPageDisplayed(Me, afterPageArgs)
        End If
    End Sub

    Public Sub AdvancePage()
        btnNext_Click(Me, Nothing)
    End Sub

    Public Sub JumpToPage(ByVal Page As Integer)
        If Page < 1 Or Page > Pages.Count Then Throw New ArgumentException("Page out of range.")
        If Page - 1 < intSelectedPage Then Throw New ArgumentException("You can only jump to a page previous to the current page.")

        intSelectedPage = Page - 1
        UpdatePage()
    End Sub

    <Browsable(False)> _
    Public ReadOnly Property NextButton() As Button
        Get
            Return btnNext
        End Get
    End Property

    <Browsable(False)> _
    Public ReadOnly Property BackButton() As Button
        Get
            Return btnBack
        End Get
    End Property

    <Browsable(False)> _
    Public ReadOnly Property CancelButton() As Button
        Get
            Return btnCancel
        End Get
    End Property

    Private Sub btnCancel_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCancel.Click
        If _CloseForm And Not (ParentForm Is Nothing) Then
            ParentForm.DialogResult = DialogResult.Cancel
        Else
            RaiseEvent Cancelled(Me, EventArgs.Empty)
        End If
    End Sub

    Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs)
        MyBase.OnHandleCreated(e)

        'Initialize buttons
        btnBack = New Button
        btnBack.Location = New Point(253, ClientRectangle.Height - 32)
        btnBack.Size = New Size(75, 23)
        btnBack.FlatStyle = FlatStyle.System
        btnBack.Text = "< " & _BackText
        btnNext = New Button
        btnNext.Location = New Point(328, ClientRectangle.Height - 32)
        btnNext.Size = New Size(75, 23)
        btnNext.FlatStyle = FlatStyle.System
        btnNext.Text = _NextText & " >"
        btnCancel = New Button
        btnCancel.Location = New Point(413, ClientRectangle.Height - 32)
        btnCancel.Size = New Size(75, 23)
        btnCancel.FlatStyle = FlatStyle.System
        btnCancel.Text = _CancelText
        If Not DesignMode Then Controls.AddRange(New Control() {btnBack, btnNext, btnCancel})

        UpdatePage()
    End Sub

    Private Sub Wizard_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
        Dim d As WizardDesigner

        If DesignMode Then
            Dim s As ISelectionService = DirectCast(GetService(GetType(ISelectionService)), ISelectionService)
            Dim h As IDesignerHost = DirectCast(GetService(GetType(IDesignerHost)), IDesignerHost)
            Dim a As New ArrayList

            If btnBack.Bounds.Contains(e.X, e.Y) Then
                'Back button
                If intSelectedPage > -1 Then
                    intSelectedPage -= 1
                    UpdatePage()
                    If intSelectedPage = -1 Then a.Add(Me) Else a.Add(Pages(intSelectedPage))
                Else
                    a.Add(Me)
                End If
            ElseIf btnNext.Bounds.Contains(e.X, e.Y) Then
                'Next button
                If intSelectedPage < Pages.Count - 1 Then
                    intSelectedPage += 1
                    UpdatePage()
                    a.Add(Pages(intSelectedPage))
                ElseIf MessageBox.Show("Would you like to add another page?", "Next Page", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
                    d = DirectCast(h.GetDesigner(Me), WizardDesigner)
                    d.OnAddPage(Nothing, Nothing)
                    a.Add(Pages(intSelectedPage))
                Else
                    a.Add(Pages(intSelectedPage))
                End If
            Else
                a.Add(Me)
            End If

            s.SetSelectedComponents(a)
        End If
    End Sub

    Protected Overrides Function CreateControlsInstance() As System.Windows.Forms.Control.ControlCollection
        Return New WizardControlCollection(Me)
    End Function

    Friend ReadOnly Property Pages() As WizardPageCollection
        Get
            Return _Pages
        End Get
    End Property

    Protected Overrides ReadOnly Property DefaultSize() As System.Drawing.Size
        Get
            Return New Size(497, 360)
        End Get
    End Property

    Protected Overrides Sub OnLayout(ByVal levent As System.Windows.Forms.LayoutEventArgs)
        Dim c As Control

        For Each c In Controls
            If c Is btnBack Then
                btnBack.Location = New Point(ClientRectangle.Width - btnCancel.Width - 9 - btnNext.Width - 10 - btnBack.Width, ClientRectangle.Height - 32)
            ElseIf c Is btnNext Then
                btnNext.Location = New Point(ClientRectangle.Width - btnCancel.Width - 9 - btnNext.Width - 10, ClientRectangle.Height - 32)
            ElseIf c Is btnCancel Then
                btnCancel.Location = New Point(ClientRectangle.Width - btnCancel.Width - 9, ClientRectangle.Height - 32)
            ElseIf TypeOf c Is WizardPage Then
                c.Bounds = New Rectangle(21, 71, ClientRectangle.Width - 41, ClientRectangle.Height - 130)
            End If
        Next
    End Sub

End Class

Friend Class WizardControlCollection
    Inherits Control.ControlCollection

    Private Wizard As Wizard

    Public Sub New(ByVal Owner As Wizard)
        MyBase.New(Owner)

        Wizard = Owner
    End Sub

    Public Overrides Sub Add(ByVal Value As Control)
        If Value Is Wizard.btnBack Or Value Is Wizard.btnNext Or Value Is Wizard.btnCancel Then
            MyBase.Add(Value)
            Return
        End If

        If Not TypeOf Value Is WizardPage Then
            Throw New ArgumentException("Control is not a WizardPage.")
        End If

        If Not Wizard.Pages.Contains(DirectCast(Value, WizardPage)) Then
            Wizard.Pages.Add(DirectCast(Value, WizardPage))
        End If

        MyBase.Add(Value)
    End Sub

    Public Overrides Sub Remove(ByVal Value As Control)
        MyBase.Remove(Value)

        If Wizard.Pages.Contains(DirectCast(Value, WizardPage)) Then
            Wizard.Pages.Remove(DirectCast(Value, WizardPage))
        End If
    End Sub
End Class